Attached patch avoids "Bad L1 flags 80" for VMX domains. Thanks Ian for
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 24 Oct 2005 07:04:38 +0000 (08:04 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 24 Oct 2005 07:04:38 +0000 (08:04 +0100)
the suggestions.

Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
xen/arch/x86/shadow.c
xen/arch/x86/shadow32.c
xen/include/asm-x86/shadow.h

index dfea7b4f43441f4e280810efa51d1cc47b64f201..fdd0c5aaf06c8c6a5901388ef0d004387d62b1c3 100644 (file)
@@ -871,6 +871,7 @@ mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
 
     perfc_incrc(shadow_mark_mfn_out_of_sync_calls);
 
+    entry->v = v;
     entry->gpfn = gpfn;
     entry->gmfn = mfn;
     entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
@@ -937,6 +938,7 @@ static void shadow_mark_va_out_of_sync(
     entry->writable_pl1e =
         l2e_get_paddr(sl2e) | (sizeof(l1_pgentry_t) * l1_table_offset(va));
     ASSERT( !(entry->writable_pl1e & (sizeof(l1_pgentry_t)-1)) );
+    entry->va = va;
 
     // Increment shadow's page count to represent the reference
     // inherent in entry->writable_pl1e
@@ -1340,6 +1342,7 @@ static int resync_all(struct domain *d, u32 stype)
             guest_l1_pgentry_t *guest1 = guest;
             l1_pgentry_t *shadow1 = shadow;
             guest_l1_pgentry_t *snapshot1 = snapshot;
+            int unshadow_l1 = 0;
 
             ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ||
                    shadow_mode_write_all(d));
@@ -1358,8 +1361,15 @@ static int resync_all(struct domain *d, u32 stype)
                 if ( (i < min_snapshot) || (i > max_snapshot) ||
                      guest_l1e_has_changed(guest1[i], snapshot1[i], PAGE_FLAG_MASK) )
                 {
-                    need_flush |= validate_pte_change(d, guest1[i], &shadow1[i]);
-                    set_guest_back_ptr(d, shadow1[i], smfn, i);
+                    int error; 
+
+                    error = validate_pte_change(d, guest1[i], &shadow1[i]);
+                    if ( error ==  -1 ) 
+                        unshadow_l1 = 1;
+                    else {
+                        need_flush |= error;
+                        set_guest_back_ptr(d, shadow1[i], smfn, i);
+                    }
                     // can't update snapshots of linear page tables -- they
                     // are used multiple times...
                     //
@@ -1371,6 +1381,19 @@ static int resync_all(struct domain *d, u32 stype)
             perfc_incrc(resync_l1);
             perfc_incr_histo(wpt_updates, changed, PT_UPDATES);
             perfc_incr_histo(l1_entries_checked, max_shadow - min_shadow + 1, PT_UPDATES);
+            if (unshadow_l1) {
+                pgentry_64_t l2e;
+
+                __shadow_get_l2e(entry->v, entry->va, &l2e);
+                if (entry_get_flags(l2e) & _PAGE_PRESENT) {
+                    entry_remove_flags(l2e, _PAGE_PRESENT);
+                    __shadow_set_l2e(entry->v, entry->va, &l2e);
+
+                    if (entry->v == current)
+                        need_flush = 1;
+                }
+            }
+
             break;
         }
 #if defined (__i386__)
index 18b5dc448fc7b5c9fe11d8642d37a6fd54104b03..5293e118431d46a32d762d3b9ccbf30b71cd2c4d 100644 (file)
@@ -1829,6 +1829,7 @@ shadow_mark_mfn_out_of_sync(struct vcpu *v, unsigned long gpfn,
 
     perfc_incrc(shadow_mark_mfn_out_of_sync_calls);
 
+    entry->v = v;
     entry->gpfn = gpfn;
     entry->gmfn = mfn;
     entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn);
@@ -1875,6 +1876,7 @@ void shadow_mark_va_out_of_sync(
     entry->writable_pl1e =
         l2e_get_paddr(sl2e) | (sizeof(l1_pgentry_t) * l1_table_offset(va));
     ASSERT( !(entry->writable_pl1e & (sizeof(l1_pgentry_t)-1)) );
+    entry->va = va;
 
     // Increment shadow's page count to represent the reference
     // inherent in entry->writable_pl1e
@@ -2320,6 +2322,7 @@ static int resync_all(struct domain *d, u32 stype)
             l1_pgentry_t *guest1 = guest;
             l1_pgentry_t *shadow1 = shadow;
             l1_pgentry_t *snapshot1 = snapshot;
+            int unshadow_l1 = 0;
 
             ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ||
                    shadow_mode_write_all(d));
@@ -2346,8 +2349,15 @@ static int resync_all(struct domain *d, u32 stype)
                 if ( (i < min_snapshot) || (i > max_snapshot) ||
                      l1e_has_changed(guest1[i], snapshot1[i], PAGE_FLAG_MASK) )
                 {
-                    need_flush |= validate_pte_change(d, guest1[i], &shadow1[i]);
-                    set_guest_back_ptr(d, shadow1[i], smfn, i);
+                    int error;
+
+                    error = validate_pte_change(d, guest1[i], &shadow1[i]);
+                    if ( error ==  -1 ) 
+                        unshadow_l1 = 1;
+                    else {
+                        need_flush |= error;
+                        set_guest_back_ptr(d, shadow1[i], smfn, i);
+                    }
 
                     // can't update snapshots of linear page tables -- they
                     // are used multiple times...
@@ -2359,6 +2369,19 @@ static int resync_all(struct domain *d, u32 stype)
             perfc_incrc(resync_l1);
             perfc_incr_histo(wpt_updates, changed, PT_UPDATES);
             perfc_incr_histo(l1_entries_checked, max_shadow - min_shadow + 1, PT_UPDATES);
+            if (unshadow_l1) {
+                l2_pgentry_t l2e;
+
+                __shadow_get_l2e(entry->v, entry->va, &l2e);
+                if (l2e_get_flags(l2e) & _PAGE_PRESENT) {
+                    l2e_remove_flags(l2e, _PAGE_PRESENT);
+                    __shadow_set_l2e(entry->v, entry->va, l2e);
+
+                    if (entry->v == current)
+                        need_flush = 1;
+                }
+            }
+
             break;
         }
         case PGT_l2_shadow:
index 93bd92aaf740a14686ece6c024856729cbb56e03..0a8112c3d3cd0971bd3310bbdb2063790da705bb 100644 (file)
@@ -302,10 +302,12 @@ struct shadow_status {
 
 struct out_of_sync_entry {
     struct out_of_sync_entry *next;
+    struct vcpu   *v;
     unsigned long gpfn;    /* why is this here? */
     unsigned long gmfn;
     unsigned long snapshot_mfn;
     unsigned long writable_pl1e; /* NB: this is a machine address */
+    unsigned long va;
 };
 
 #define out_of_sync_extra_size 127
@@ -384,6 +386,10 @@ shadow_get_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
 
     nl1e = l1e;
     l1e_remove_flags(nl1e, _PAGE_GLOBAL);
+
+    if ( unlikely(l1e_get_flags(l1e) & L1_DISALLOW_MASK) )
+        return 0;
+
     res = get_page_from_l1e(nl1e, d);
 
     if ( unlikely(!res) && IS_PRIV(d) && !shadow_mode_translate(d) &&
@@ -959,14 +965,16 @@ validate_pte_change(
             //
             perfc_incrc(validate_pte_changes3);
 
-            if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) &&
-                 !shadow_get_page_from_l1e(new_spte, d) )
-                new_spte = l1e_empty();
             if ( l1e_get_flags(old_spte) & _PAGE_PRESENT )
             {
                 shadow_put_page_from_l1e(old_spte, d);
                 need_flush = 1;
             }
+            if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) &&
+                 !shadow_get_page_from_l1e(new_spte, d) ) {
+                new_spte = l1e_empty();
+                need_flush = -1; /* need to unshadow the page */
+            }
         }
         else
         {